<template>
    <div class="high-search">
        <div class="fuzzy-box">
            <el-select
                :key="selectKey"
                v-model="selectedVal"
                :disabled="disabled"
                :loading="loading"
                filterable
                remote
                collapse-tags
                :clearable="false"
                :multiple="!highSearchConfig.dialogSearchConfig.isSingleSelect"
                :remote-method="remoteMethod"
                style="width: 100%"
                :placeholder="placeholder ? $t(placeholder) : $t('form.placeholder.input', { msg: '' })"
                @clear="
                    () => {
                        highSearchConfig.clearHandle && handleChange();
                    }
                "
                @visible-change="selectFocus"
                @change="handleChange"
            >
                <el-option
                    v-for="item in optionsData"
                    :key="item.value"
                    :label="item.code && item.label ? `${item.code}-${item.label}` : item.label || item.code"
                    :value="item.value"
                >
                    <span v-if="item.code">{{ item.code }}</span>
                    <span v-if="item.code && item.label">-</span>
                    <span v-if="item.label">{{ item.label }}</span>
                </el-option>
            </el-select>

            <el-button icon="el-icon-more" class="box" :disabled="disabled" @click="openHighSearch" />
            <div v-if="hideText" class="hide-text" :class="[disabled ? 'bd-disable' : 'bd-f']">
                <p class="f12">高级搜索</p>
                <el-tooltip class="item" effect="dark" content="清空会删除高级搜索条件" placement="top-end">
                    <i class="el-icon-circle-close close-btn hover" @click="close" />
                </el-tooltip>
            </div>
        </div>
        <high-search-dialog
            ref="highSearch"
            :defaultFilter="defaultFilter"
            :dialogData="highSearchConfig.dialogSearchConfig"
            :requestExtend="highSearchConfig.requestExtend"
            :dialogObj="highSearchDialogObj"
            class="high-search"
            v-on="$listeners"
            @singleChannelChoose="singleChannelChoose"
            @confirm="confirmSearchOption"
        />
    </div>
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop } from 'vue-property-decorator';
import { Response, HighSearchConfig, DialogObj, Dictionary } from '@/typings';
import { transformFields, formatHighSearchCascader } from '@/utils';
import { WatchMounted } from '@/utils/decorator';

@Component({
    name: 'advanced-fuzzy',
    components: {
        highSearchDialog: () => import('@/layout-components/vip-dialog/index.vue')
    }
})
export default class App extends Vue {
    /** defaultFilter 说明
     *
     *  目前只做了内嵌高筛选/下拉选择框
     *
     defaultFilter:{
         // 普通下拉
         priceTypeIds:{
             value: val,    ——————value 数组类型=多选  , 字符串=单选
             disabled: true,
             // options: this.formList[6].options 不用传
         }
         // 高筛选
         toChannelId:{
           value: [value],   ——————value 数组类型=多选  , 字符串=单选
           label: matchValArr[0].label,   —————— 单选需要赋值  多选不需要
           options: [{ label: matchValArr[0].label, value: value }], ——————多选需要赋值  单选不需要
           disabled: true
         }
      }
     * */
    @Prop({
        default: () => {
            return {};
        }
    })
    defaultFilter: object;
    @Prop({ default: true }) clearable: boolean;
    @Prop({ default: '' }) placeholder: string;
    @Prop({ default: false }) disabled: boolean;
    @Prop({ required: true }) highSearchConfig: HighSearchConfig;
    @Prop({ required: true }) value: any; // 绑定的值
    @Prop({ required: true }) formData: Dictionary; // 这里是表单全量的数据 主要用于数据的回显 需要获取对应ID 的 code name
    @Prop({ required: true }) type: string; // key值
    @Prop({})
    rollbackFormat: Function;
    // @DistributeName('advanced-fuzzy')
    // $onTest(value) {
    //   console.log('子组件接受派发', value)
    // }
    @WatchMounted('formData.id')
    onIdChange(val) {
        if (val) {
            this.setOptionsData();
        }
    }
    @WatchMounted('value', { immediate: true })
    onValueChanged(val: any, oldVal: any) {
        this.selectedVal = val;
        this.updateValue(oldVal);

        if (val) {
            const key = `${this.type.replace('Id', '')}`;
            if (this.rollbackFormat && this.rollbackFormat(this.formData)) {
                this.setOptionsData();
            }
            if (!!this.formData[`${key}Code`] && !!this.formData[`${key}Name`]) {
                this.setOptionsData();
            }
            // 如果是数组则要清空高级搜索里面的查询条件
            if (val.length === 0) {
                this.close();
            }
        }
    }
    // 存储上一次的数据
    lastDate: Dictionary = {};
    selectedVal: any = '';
    loading: boolean = true;
    hideText: boolean = false;
    optionsData: any[] = [];
    query: string = '';
    selectKey: number = 1;
    highSearchDialogObj: DialogObj = {
        isShowDialog: false,
        title: '',
        appendToBody: true,
        modal: true,
        setShow: true
    };

    selectFocus() {
        if (this.optionsData.length <= 1) {
            this.getData(this.query || '');
        }
    }
    // method
    async getData(query: string) {
        // 获取模糊搜索数据
        // 👇 外层props拓展进来额外参数
        const other = {};
        (Object.keys(this.defaultFilter) as any).forEach((em) => {
            other[em] = this.defaultFilter[em].value || undefined;
        });
        // 👇 定义的时候拓展进来额外参数
        if (this.highSearchConfig.requestExtend) {
            Object.assign(other, this.highSearchConfig.requestExtend);
        }
        if (this.highSearchConfig.customerQuery) {
            this.$emit('getFilterOptions', { query });
            return;
        }

        const res: Response = await this._post({
            url: this.highSearchConfig.dialogSearchConfig.api!,
            data: {
                page: 1,
                pageSize: 50,
                data: {
                    // 直接两个keyword 给后台爱取哪个就取哪个
                    keyword: query || undefined,
                    // keyWord: query || undefined,
                    ...other
                }
            }
        });
        if (res.code === 0) {
            this.loading = false;
            this.optionsData = transformFields(
                res.data,
                {
                    label: this.highSearchConfig.auxiliaryMatch || 'name',
                    code: 'code',
                    value: 'id'
                },
                true
            );
        }
    }

    remoteMethod(query: string) {
        // 模糊搜索
        this.query = query.trim();
        if (this.query !== '') {
            const f = this._debounce(() => {
                this.getData(this.query);
            }, 500);
            f();
        }
    }

    handleChange(value) {
        const valueArr = Array.isArray(value) ? value : [value];
        const matchValArr = this.optionsData.filter((item) => valueArr.includes(item.value));

        this.$emit('update:value', value);
        // 旧版本
        this.$emit(`${this.type}-fuzzyChange`, { value, matchValArr });

        // 新版本支持函数返回值【true/false】回滚上次数据 true = 通过 /false = 回滚
        this.$nextTick(() => {
            // 确保watch已执行
            this.$emit('fuzzyChangeRollBACK', async (Function) => {
                const RollBACK = await Function({
                    value,
                    matchValArr,
                    senior: false,
                    lastValue: this.lastDate.value
                });
                if (RollBACK === false) {
                    this.rollBackValue();
                }
            });
        });
    }
    // 打开高级搜索弹窗
    openHighSearch() {
        this.highSearchDialogObj.isShowDialog = true;
        this.highSearchDialogObj.width = this.highSearchConfig.dialogSearchConfig.dialogWidth || '970px';
        this.highSearchDialogObj.title = this.$t(this.highSearchConfig.dialogSearchConfig.title);
    }
    // 清除 高级搜索的条件值 并且清空高级搜索弹窗的条件
    close() {
        this.hideText = false;
        // 清空条件值
        this.$emit('updateAdvancedSearchValue', '');
        // 清空弹窗里面的条件
        (this.$refs.highSearch as any).reset();
    }
    setOptionsData() {
        const key = `${this.type.replace('Id', '')}`;

        const label = this.rollbackFormat ? this.rollbackFormat(this.formData) : this.formData[`${key}Name`] || this.formData[`${key}BillNo`];
        this.$nextTick(() => {
            this.optionsData = [
                {
                    label,
                    code: this.formData[`${key}Code`] || '',
                    value: this.formData[this.type]
                }
            ];
            this.selectedVal = this.formData[this.type];
            this.selectKey += 1;
        });
    }
    upDateOptionsData(arr, value?) {
        this.optionsData = arr;
        this.selectedVal = '';
        setTimeout(() => {
            this.$nextTick(() => {
                value && (this.selectedVal = value);
                this.selectKey += 1;
            });
        }, 500);
    }

    // 多选渠道的选择
    confirmSearchOption(queryFormData) {
        // 如果 筛选条件中 有级联的 则需要对其数据进行处理 只取 选择的最后一个的 id
        // 找到 有级联的 筛选条件
        const formlist = this.highSearchConfig.dialogSearchConfig.formList;
        const cascaderVal = {};
        for (var k in queryFormData) {
            cascaderVal[k] = Object.assign(
                {},
                queryFormData[k],
                // 匹配到级联字段则对值 进行处理 如 [ [1,2], [3,4] ] => [ 2,4 ]
                formatHighSearchCascader(formlist, queryFormData[k])
            );
        }
        // 这里是 高级搜索 则 手动去外层组件 更新数据
        this.$emit('updateAdvancedSearchValue', cascaderVal);
        this.hideText = true;
    }

    // 用于绑定弹窗选择
    singleChannelChoose(value) {
        this.$emit('update:value', value.row.id);

        this.$emit(`${this.type}-fuzzyChange`, {
            value: value.row.id,
            matchValArr: [value.row]
        });
        this.$nextTick(() => {
            const label = this.rollbackFormat ? this.rollbackFormat(value.row) : `${value.row.name}`;
            this.optionsData = [
                {
                    label: label,
                    value: value.row.id,
                    code: value.row.code
                }
            ];
            this.$emit('fuzzyChangeRollBACK', async (Function) => {
                const RollBACK = await Function({
                    value: value.row.id,
                    matchValArr: [value.row],
                    senior: true,
                    lastValue: this.lastDate.value
                });
                if (RollBACK === false) {
                    this.rollBackValue();
                }
            });
        });
    }
    // 更新旧值
    updateValue(value: string | number) {
        const index = this.optionsData.findIndex((item) => {
            return item.value === value;
        });
        this.$set(this, 'lastDate', {
            value,
            options: index > -1 ? [this.optionsData[index]] : []
        });
    }
    // 回滚
    rollBackValue() {
        const { options, value } = this.lastDate;
        this.optionsData = options;
        this.$nextTick(() => {
            this.$emit('update:value', value);
        });
    }
}
</script>

<style scoped lang="scss">
.fuzzy-box {
    display: flex;
    align-items: center;
    /deep/.el-input__inner {
        border-radius: 2px 0 0 2px;
    }
}
.hide-text {
    display: flex;
    align-items: center;
    justify-content: space-between;
    // background: #fff;
    position: absolute;
    left: 10px;
    width: 84%;
    height: 23px;
    line-height: 23px;
    top: 2px;
    padding: 0 4px;
    font-size: 12px;
    z-index: 1000;
}
.bd-disable {
    background: #f5f7fa;
}
.bd-f {
    background: #fff;
}
.close-btn {
    display: inline-block;
    padding: 2px;
}
.box {
    width: 32px;
    height: 26px;
    border: 1px solid #d7d7d7;
    border-radius: 0px 2px 2px 0px;
    border-left: none;
    background: #f7f8fa !important;
    // text-align: center;
    // display: flex;
    // align-items: center;
    // justify-content: center;
    // &:hover {
    //   cursor: pointer;
    // }
    .radis {
        display: inline-block;
        border: 2px solid #a6a7ad;
        border-radius: 100%;
        margin-right: 2px;
    }
}
</style>
